import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { In, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { RoleService } from '../role/role.service';
import * as bcrypt from 'bcryptjs';
import { saltRounds } from 'src/common/constant/constant';
import { LoginUserDto } from '../auth/dto/login-user.dto';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly repository: Repository<User>,
    private readonly roleService: RoleService,
  ) {}
  async create(createUserDto: CreateUserDto) {
    return await this.repository.save(createUserDto);
  }

  async saveList(users: User[]) {
    const entities = users.map((v) => {
      return this.repository.create(v);
    });
    return await this.repository.save(entities);
  }

  async addRole(userId: number, roleId: number) {
    const user = await this.findOneWithRoles(userId);
    const role = await this.roleService.findOne(roleId);
    user.roles = user.roles || [];
    user.roles.push(role);
    return await this.repository.save(user);
  }

  async findAll() {
    return await this.repository.find();
  }

  async findOne(id: number) {
    return await this.repository.findOneBy({ id });
  }

  async findOneWithRoles(id: number) {
    // return await this.repository.find({ where: { id }, relations: ['roles'] });
    return await this.repository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'role')
      .where('user.id = :id', { id })
      .getOne();
  }

  async getDetailByUsername(username: string) {
    return await this.repository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'role')
      .leftJoinAndSelect('role.permissions', 'permission')
      .where('user.username = :username', { username })
      .getOne();
  }

  async update(id: number, updateUserDto: UpdateUserDto) {
    return await this.repository.update(id, updateUserDto);
  }

  async remove(id: number) {
    return await this.repository.delete(id);
  }

  async findByIdCard(idCards: string[]) {
    return await this.repository.find({ where: { idCard: In(idCards) } });
  }

  async findByUsername(username: string): Promise<User | undefined> {
    return this.repository.findOne({ where: { username } });
  }
  async register(createUserDto: CreateUserDto) {
    const user = await this.findByUsername(createUserDto.username);
    if (user) {
      throw new HttpException('用户名已存在', HttpStatus.INTERNAL_SERVER_ERROR);
    }
    createUserDto.password = await bcrypt.hash(
      createUserDto.password,
      saltRounds,
    );
    return await this.create(createUserDto);
  }
  async changePassword(createUserDto: LoginUserDto) {
    const user = await this.findByUsername(createUserDto.username);
    if (!user) {
      throw new HttpException('用户名不存在', HttpStatus.INTERNAL_SERVER_ERROR);
    }
    user.password = await bcrypt.hash(createUserDto.password, saltRounds);
    await this.create(user);
  }
}
